/**
 * @file prv_rtk_macro.h
 * @author LokLiang (lokliang@163.com)
 * @brief
 * @version 0.1
 * @date 2023-05-01
 *
 * @copyright Copyright (c) 2023
 *
 */

#ifndef __PRV_RTK_MACRO_H__
#define __PRV_RTK_MACRO_H__

#include "rtk_config.h"

#ifdef __cplusplus
extern "C"
{
#endif /* #ifdef __cplusplus */

#define RTK_LOG_LEVEL_OFF 0
#define RTK_LOG_LEVEL_ERR 1
#define RTK_LOG_LEVEL_WRN 2
#define RTK_LOG_LEVEL_INF 3
#define RTK_LOG_LEVEL_DBG 4

#ifndef CONFIG_RTK_LOG_LEVEL
#define CONFIG_RTK_LOG_LEVEL RTK_LOG_LEVEL_INF
#endif

#ifndef CONFIG_RTK_MAX_PRIORITY
#define CONFIG_RTK_MAX_PRIORITY 31 /* 最大线程优先级（值 31 为最优） */
#endif

#ifndef CONFIG_RTK_TICKS_HZ
#define CONFIG_RTK_TICKS_HZ 1000 /* 默认时钟节拍频率 */
#endif

#ifndef CONFIG_RTK_STACK_CHECK
#define CONFIG_RTK_STACK_CHECK CONFIG_RTK_ERR_ON /* 允许记录线程栈用量 */
#endif

#ifndef CONFIG_RTK_POSIX_ERRNO
#define CONFIG_RTK_POSIX_ERRNO 0 /* 使用线程错误码 */
#endif

#ifndef CONFIG_RTK_ISR_SUPPORT
#define CONFIG_RTK_ISR_SUPPORT 0 /* 是否使所有接口允许中断使用 */
#endif

#if defined(__CC_ARM) || defined(__GNUC__)

#if CONFIG_RTK_MAX_PRIORITY > 255
#error Defined CONFIG_RTK_MAX_PRIORITY > 255
#endif // #if CONFIG_RTK_MAX_PRIORITY > 255

#else // #if defined(__CC_ARM) || defined(__GNUC__)

#if CONFIG_RTK_MAX_PRIORITY > 63
#error Defined CONFIG_RTK_MAX_PRIORITY > 63
#endif // #if CONFIG_RTK_MAX_PRIORITY > 63

#endif // #if defined(__CC_ARM) || defined(__GNUC__)

#ifndef SYS_LOG_DOMAIN
#define SYS_LOG_DOMAIN "rtk"
#endif
#include "sys_log.h"

#define CONFIG_RTK_TRACE_ON (CONFIG_RTK_LOG_LEVEL >= RTK_LOG_LEVEL_DBG)
#define CONFIG_RTK_ASS_ON (CONFIG_RTK_LOG_LEVEL >= RTK_LOG_LEVEL_INF)
#define CONFIG_RTK_INF_ON (CONFIG_RTK_LOG_LEVEL >= RTK_LOG_LEVEL_INF)
#define CONFIG_RTK_WRN_ON (CONFIG_RTK_LOG_LEVEL >= RTK_LOG_LEVEL_WRN)
#define CONFIG_RTK_ERR_ON (CONFIG_RTK_LOG_LEVEL >= RTK_LOG_LEVEL_ERR)

#define _RTK_TRACE_ENTRY()                                  \
    struct                                                  \
    {                                                       \
        slist_node_t node;                                  \
        const char *func;                                   \
    } trace;                                                \
    do                                                      \
    {                                                       \
        if (CONFIG_RTK_TRACE_ON)                            \
        {                                                   \
            _rtk_service_trace_entry(&trace, __FUNCTION__); \
        }                                                   \
    } while (0)

#define _RTK_TRACE_EXIT()                    \
    do                                       \
    {                                        \
        if (CONFIG_RTK_TRACE_ON)             \
        {                                    \
            _rtk_service_trace_exit(&trace); \
        }                                    \
    } while (0)

#define _RTK_WRN(FMT, ...)                   \
    do                                       \
    {                                        \
        if (CONFIG_RTK_WRN_ON)               \
        {                                    \
            SYS_LOG_WRN(FMT, ##__VA_ARGS__); \
        }                                    \
    } while (0)

#define _RTK_ASS_FALSE(FLAG, FMT, ...)                  \
    do                                                  \
    {                                                   \
        if (CONFIG_RTK_ASS_ON)                          \
        {                                               \
            SYS_ASSERT_FALSE(FLAG, FMT, ##__VA_ARGS__); \
        }                                               \
    } while (0)

#define _RTK_CHECK_HEAP(M)                                                                           \
    do                                                                                               \
    {                                                                                                \
        if (CONFIG_RTK_ERR_ON)                                                                       \
        {                                                                                            \
            if (rtk_heap_is_valid(M) == false)                                                       \
            {                                                                                        \
                CONS_PRINT(_COLOR_RY "[ASS]" _COLOR_END " # %s:%d, %s(): Memory corruption: %p\r\n", \
                           _FILENAME(__FILE__), __LINE__, __FUNCTION__, M);                          \
                rtk_cpu_interrupt_save();                                                            \
                for (;;)                                                                             \
                    ;                                                                                \
            }                                                                                        \
        }                                                                                            \
        else if (CONFIG_RTK_WRN_ON)                                                                  \
        {                                                                                            \
            bool ass = rtk_heap_is_valid(M);                                                         \
            if (ass != RTK_OK)                                                                       \
            {                                                                                        \
                rtk_cpu_interrupt_save();                                                            \
                for (;;)                                                                             \
                    ;                                                                                \
            }                                                                                        \
        }                                                                                            \
    } while (0)

#define _RTK_CHECK_HEAPK(M)                                                                          \
    do                                                                                               \
    {                                                                                                \
        if (CONFIG_RTK_ERR_ON)                                                                       \
        {                                                                                            \
            if (rtk_heapk_is_valid(M) == false)                                                      \
            {                                                                                        \
                CONS_PRINT(_COLOR_RY "[ASS]" _COLOR_END " # %s:%d, %s(): Memory corruption: %p\r\n", \
                           _FILENAME(__FILE__), __LINE__, __FUNCTION__, M);                          \
                rtk_cpu_interrupt_save();                                                            \
                for (;;)                                                                             \
                    ;                                                                                \
            }                                                                                        \
        }                                                                                            \
        else if (CONFIG_RTK_WRN_ON)                                                                  \
        {                                                                                            \
            bool ass = rtk_heapk_is_valid(M);                                                        \
            if (ass != RTK_OK)                                                                       \
            {                                                                                        \
                return RTK_E_MEM;                                                                    \
            }                                                                                        \
        }                                                                                            \
    } while (0)

#define _RTK_CHECK_THREAD(HANDLE)                                                     \
    do                                                                                \
    {                                                                                 \
        if (CONFIG_RTK_ERR_ON)                                                        \
        {                                                                             \
            if (_rtk_service_assert_check_thread(                                     \
                    1, (rtk_thread_t *)(HANDLE), __FILE__, __LINE__, __FUNCTION__) != \
                RTK_OK)                                                               \
            {                                                                         \
                rtk_cpu_interrupt_save();                                             \
                for (;;)                                                              \
                    ;                                                                 \
            }                                                                         \
        }                                                                             \
        else if (CONFIG_RTK_WRN_ON)                                                   \
        {                                                                             \
            rtk_err_t ass = _rtk_service_assert_check_thread(                         \
                3, (rtk_thread_t *)(HANDLE), __FILE__, __LINE__, __FUNCTION__);       \
            if (ass != RTK_OK)                                                        \
            {                                                                         \
                return ass;                                                           \
            }                                                                         \
        }                                                                             \
    } while (0)

#define _RTK_CHECK_HANDLE_ERR(HANDLE)                               \
    do                                                              \
    {                                                               \
        if (CONFIG_RTK_ERR_ON)                                      \
        {                                                           \
            if (_rtk_service_assert_check_handle(                   \
                    1, HANDLE, __FILE__, __LINE__, __FUNCTION__) != \
                RTK_OK)                                             \
            {                                                       \
                rtk_cpu_interrupt_save();                           \
                for (;;)                                            \
                    ;                                               \
            }                                                       \
        }                                                           \
        else if (CONFIG_RTK_WRN_ON)                                 \
        {                                                           \
            rtk_err_t ass = _rtk_service_assert_check_handle(       \
                3, HANDLE, __FILE__, __LINE__, __FUNCTION__);       \
            if (ass != RTK_OK)                                      \
            {                                                       \
                return ass;                                         \
            }                                                       \
        }                                                           \
        else if (*(void **)HANDLE == NULL)                          \
        {                                                           \
            _RTK_TRACE_EXIT();                                      \
            return RTK_E_HDL;                                       \
        }                                                           \
    } while (0)

#define _RTK_CHECK_HANDLE(HANDLE)                                   \
    do                                                              \
    {                                                               \
        if (CONFIG_RTK_ERR_ON)                                      \
        {                                                           \
            if (_rtk_service_assert_check_handle(                   \
                    1, HANDLE, __FILE__, __LINE__, __FUNCTION__) != \
                RTK_OK)                                             \
            {                                                       \
                rtk_cpu_interrupt_save();                           \
                for (;;)                                            \
                    ;                                               \
            }                                                       \
        }                                                           \
        else if (CONFIG_RTK_WRN_ON)                                 \
        {                                                           \
            rtk_err_t ass = _rtk_service_assert_check_handle(       \
                3, HANDLE, __FILE__, __LINE__, __FUNCTION__);       \
            if (ass != RTK_OK)                                      \
            {                                                       \
                return NULL;                                        \
            }                                                       \
        }                                                           \
        else if (*(void **)HANDLE == NULL)                          \
        {                                                           \
            _RTK_TRACE_EXIT();                                      \
            return NULL;                                            \
        }                                                           \
    } while (0)

#define _DO_RTK_CHECK_ISR()                                     \
    do                                                          \
    {                                                           \
        if (CONFIG_RTK_ERR_ON &&                                \
            curr_thread_handle != NULL && rtk_is_isr_context()) \
        {                                                       \
            _rtk_service_isr_check_log(__FUNCTION__);           \
        }                                                       \
    } while (0)

#define _RTK_CHECK_SWAP(T)                              \
    do                                                  \
    {                                                   \
        if (CONFIG_RTK_WRN_ON && T != 0 &&              \
            (cm_rtk->nest_int | cm_rtk->nest_sched))    \
        {                                               \
            _rtk_service_isr_check_sched(__FUNCTION__); \
        }                                               \
    } while (0)

#define _RTK_CHECK_ISR()                 \
    do                                   \
    {                                    \
        if (CONFIG_RTK_ISR_SUPPORT != 1) \
        {                                \
            _DO_RTK_CHECK_ISR();         \
        }                                \
    } while (0)

#define _RTK_TICK_LIMIT(N)                    \
    do                                        \
    {                                         \
        if ((unsigned int)N > _SIGNED_MAX(N)) \
        {                                     \
            N = _SIGNED_MAX(N);               \
        }                                     \
    } while (0)

#define _RTK_THREAD_FLAG_HEAP (1 << 0)  /* 任务栈来自堆分配 */
#define _RTK_THREAD_FLAG_SYS (1 << 1)   /* 系统线程 */
#define _RTK_THREAD_FLAG_SEM (1 << 2)   /* 成功等待信号量 */
#define _RTK_THREAD_FLAG_WORKQ (1 << 3) /* 工作队列线程 */

#define _ARRAY_COUNT(A) (sizeof(A) / sizeof(A[0]))
#define _SIGNED_MAX(N) ((int)((1u << (sizeof(N) * 8 - 1)) - 1))
#define _SIGNED_MIN(N) ((int)(1u << (sizeof(N) * 8 - 1)))
#define _RTK_HEAP_DET_VALUE 0x9FEDCBA1 /* 内存未被改写的标记值 */
#define _RTK_CONTAINER_OF(PTR, TYPE, MEMBER) ((TYPE *)&((uint8_t *)PTR)[-(int)&((TYPE *)0)->MEMBER])
#define _RTK_UNUSE(N) ((void)(N))

#ifdef __cplusplus
} /* extern "C" */
#endif /* #ifdef __cplusplus */

#endif
